package com.megurokai.paint;

import com.megurokai.command.Command;
import com.megurokai.tool.Tool;
import com.megurokai.tool.ToolBrush;
import com.megurokai.tool.ToolPencil;
import com.megurokai.tool.ToolScroll;
import com.megurokai.tool.ToolZoom;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.view.Display;
import android.view.MotionEvent;
import android.view.ScaleGestureDetector;
import android.view.WindowManager;

public class PaintManager{
	public final static int DEFAULT_TARGET_LAYER = 0;
	protected final static int DEFAULT_WIDTH = 480;
	protected final static int DEFAULT_HEIGHT = 480;
	protected final static Boolean sync = new Boolean(true);
	private static PaintManager instance = new PaintManager();
	
	protected PaintView view;
	protected float zoomRate;
	protected float offsetX;
	protected float offsetY;
	protected float baseX;
	protected float baseY;
	protected float infoHeight;
	protected Tool tool;
	protected ToolBrush toolBrush;
	protected ToolPencil toolPencil;
	protected ToolScroll toolScroll;
	protected ToolZoom toolZoom;
	protected Boolean lock;
	protected Paint paint;
	protected Status status;
	protected HistoryManager history;
	protected Callback<Status> callback;
	
	private PaintManager(){
		callback = null;
		
		init();
		reset();
	}
	private PaintManager(PaintView view) {
		this.view = view;
		callback = null;
		
		init();
		reset();
	}

	public static PaintManager getInstance(){
		return instance;
	}
	
	private void init(){
		lock = false;
		
		toolPencil = new ToolPencil(this);
		toolBrush = new ToolBrush(this);
		toolZoom = new ToolZoom(this);
		toolScroll = new ToolScroll(this);
		
		status = new Status();
		status.setColor(Color.RED);
		status.setStrokeWidth(3);
		status.setWidth(DEFAULT_WIDTH);
		status.setHeight(DEFAULT_HEIGHT);
		status.setDefault(status);
		
		history = new HistoryManager();
	}
	private void reset(){
		synchronized(sync){
			zoomRate = 1.0f;
			infoHeight = 0;
			status.reset();
			offsetX = status.getWidth()/2;
			offsetY = status.getHeight()/2;
			history.clear();
		}
	}
	
	// 画面描画間隔を返す
	public long getUpdateInterval(){
		return 10;
	}
	
	// 画面を描画する
	public void draw(Canvas canvas){
		synchronized(sync){
			int width = canvas.getWidth();
			int height = canvas.getHeight();
			
			if(status.getScreen() == null){
				initScreen(canvas, width, height);
			}
			
			Bitmap screen = status.getScreen();
			if(screen != null){
				
				Rect src = new Rect(0, 0, screen.getWidth(), screen.getHeight());
				Rect dst = new Rect((int)toScreenX(0), (int)toScreenY(0),
						(int)toScreenX(screen.getWidth()), (int)toScreenY(screen.getHeight()));
				Paint paint = new Paint();
				paint.setStyle(Paint.Style.FILL);
				canvas.drawColor(Color.rgb(0x40, 0x40, 0x40));
				int cuts = 16;
				float rectWidth = dst.width();
				float rectHeight = dst.height();
				
				for(int y=0; y<cuts; y++){
					for(int x=0; x<cuts; x++){
						if((x+y)%2 == 0){
							paint.setColor(Color.rgb(0xa0, 0xa0, 0xa0));
						}else{
							paint.setColor(Color.rgb(0x80, 0x80, 0x80));
						}
						
						float left = dst.left+x*rectWidth/cuts;
						float top = dst.top+y*rectHeight/cuts;
						float right = left+rectWidth/cuts;
						float bottom = top+rectHeight/cuts;
						canvas.drawRect(left, top, right, bottom, paint);
					}
				}
				//canvas.drawRect(dst, paint);
				canvas.drawBitmap(screen, src, dst, null);
			}
		}
	}
	
	// スクリーンを初期化する
	private void initScreen(Canvas canvas, float width, float height){
		synchronized(sync){
			baseX = width / 2;
			baseY = height / 2;
			
			WindowManager wm = (WindowManager)view.getContext().getSystemService(Context.WINDOW_SERVICE);
			Display disp = wm.getDefaultDisplay();
			infoHeight = disp.getHeight() - height;
			
			offsetX = DEFAULT_WIDTH / 2;
			offsetY = DEFAULT_HEIGHT / 2;
			Bitmap screen = Bitmap.createBitmap(DEFAULT_WIDTH, DEFAULT_HEIGHT, Bitmap.Config.ARGB_8888);
			Canvas c = new Canvas(screen);
			c.drawColor(Color.WHITE);
			status.addLayer(screen);
		}
	}
	
	// 論理X座標をスクリーンX座標に変換
	public float toScreenX(float val){
		float result = baseX + (val - offsetX) * zoomRate;
		return result;
	}

	// 論理X座標をスクリーンX座標に変換
	public float toScreenY(float val){
		float result = baseY + (val - offsetY) * zoomRate;
		return result;
	}

	// スクリーンX座標を論理X座標に変換
	public float toModelX(float val){
		float result = (val - baseX) / zoomRate + offsetX;
		return result;
	}

	// スクリーンY座標を論理Y座標に変換
	public float toModelY(float val){
		float result = (val - baseY) / zoomRate + offsetY;
		return result;
	}
	
	// ツールをブラシに変更
	public void setBrush(){
		tool = toolBrush;
	}
	
	// ツールを鉛筆に変更
	public void setPencil(){
		tool = toolPencil;
	}
	
	// ツールを移動に変更
	public void setScroll(){
		tool = toolScroll;
	}
	
	// ツールをズームに変更
	public void setZoom(){
		tool = toolZoom;
	}
	
	// アンドゥを実行
	public void undo(){
		history.undo(status);
	}
	
	// リドゥを実行
	public void redo(){
		history.redo(status);
	}
	
	// コマンドを受け取る
	public void sendCommand(Command command){
		history.addAndDraw(command, status);
	}
	public void replaceCommand(Command command){
		history.replace(command);
		// コマンドを受け取ったが、置き換え指定のコマンドは
		// 直前のコマンドと同じ動作をするのでコマンド実行はしない
	}
	
	// イベントハンドラ
	public boolean onTouchUp(MotionEvent event){
		return tool.onTouchUp(event);
	}
	public boolean onTouchDown(MotionEvent event){
		return tool.onToudhDown(event);
	}
	public boolean onTouchMove(MotionEvent event){
		return tool.onTouchMove(event);
	}
	public boolean onScale(ScaleGestureDetector det) {
		return tool.onScale(det);
	}
	public boolean onScaleBegin(ScaleGestureDetector det) {
		return tool.onScaleBegin(det);
	}
	public void onScaleEnd(ScaleGestureDetector det) {
		tool.onScaleEnd(det);
	}
	public void onOptionMenu(){
		synchronized(sync){
			if(getLock() == true) return ;
		
			reset();
		}
	}
	
	// セッターゲッター
	public void setCallback(Callback<Status> callback){
		this.callback = callback;
	}
	
	public void setView(PaintView view){
		this.view = view;
		
		baseX = view.getScreenWidth() / 2;
		baseY = view.getScreenHeight() / 2;
	}
	
	public int getColor(){
		return paint.getColor();
	}
	public void setColor(int color){
		paint.setColor(color);
	}
	public float getInfoHeight(){
		return infoHeight;
	}
	public float getZoomRate() {
	    return zoomRate;
	}
	public void setZoomRate(float zoomRate) {
	    this.zoomRate = zoomRate;
	}
	public float getOffsetX() {
	    return offsetX;
	}
	public void setOffsetX(float offsetX) {
	    this.offsetX = offsetX;
	}
	public float getOffsetY() {
	    return offsetY;
	}
	public void setOffsetY(float offsetY) {
	    this.offsetY = offsetY;
	}
	public boolean getLock() {
	    return lock;
	}
	public void setLock(boolean lock) {
	    this.lock = lock;
	}
	public Status getStatus() {
	    return status;
	}
	public void setStatus(Status status) {
	    this.status = status;
	}
	public void setStrokeWidth(int value){
		status.setStrokeWidth(value);
	}
	public void setAlpha(int value){
		status.setAlpha(value);
	}
}
